/**
 * THPS Dedicated Server
**/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef WIN32
    #include <winsock.h>
    #include "winerr.h"

    #define  close closesocket

    /** Windows Threading **/
    #define THREAD(NAME,ARG)  DWORD WINAPI NAME(ARG)
    #define THREADX(TH,TID,THR,PAR) \
        TH = CreateThread(NULL, 0, (void *)&THR, (void *)PAR, 0, &TID); \
        if(!TH) { \
            fputs("\nError: Unable to create thread\n", stdout); \
            exit(1); \
        }

    DWORD   tid;
    HANDLE  th;
#else
    /** *nix includes **/

    /** *nix Threading **/
    #define THREAD(NAME,ARG)  void *NAME(ARG)
    #define THREADX(TH,TID,THR,PAR) \
        TH = pthread_create(&TID, NULL, (void *)&THR, (void *)PAR); \
        if(TH) { \
            fputs("\nError: Unable to create thread\n", stdout); \
            exit(1); \
        }

    pthread_t   tid;
    int         th;
#endif

#include "main.h"

int main( int argc, char **argv ) {
    int sd1, sd2;
    struct sockaddr_in serv_addr, client_addr;
    int yes = 1, sin_size;

#ifdef WIN32
    WSADATA wsaData;

    if( WSAStartup(MAKEWORD(1, 1), &wsaData) != 0 )
    {
        fprintf(stderr, "[!!] WSAStartup failed\n");
        exit(1);
    }
#endif

    if( (sd1 = socket(PF_INET, SOCK_STREAM, 0)) == -1 )
    {
        perror("socket");
        exit(1);
    }

    if( setsockopt(sd1, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1 )
    {
        perror("setsockopt");
        exit(1);
    }

    serv_addr.sin_family        = AF_INET;
    serv_addr.sin_port          = htons(PORT);
    serv_addr.sin_addr.s_addr   = INADDR_ANY;
    memset(serv_addr.sin_zero, '\0', sizeof serv_addr.sin_zero);

    if( bind(sd1, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1 )
    {
        perror("bind");
        exit(1);
    }

    if( listen(sd1, MAX_CONNECT) == -1 )
    {
        perror("listen");
        exit(1);
    }


    while(1)
    {
        sin_size = sizeof(struct sockaddr_in);

        if( (sd2 = accept(sd1, (struct sockaddr *)&client_addr, &sin_size)) == -1 )
        {
            perror("accept");
            continue;
        }

        DEBUG_PRINT("Connection from %s\n", inet_ntoa(client_addr.sin_addr));

        THREADX(th, tid, HandleClient, sd2);
    }

    close(sd1);
return 0;
}

THREAD( HandleClient,int sd )
{

    puts("Handled... closed");
    close(sd);
}

void DEBUG_PRINT( unsigned char *str, ... )
{
    va_list list;
    FILE *fd = stdout;

    if( DEBUG )
    {
        if( DEBUG_FILE != NULL )
        {
            if( !(fd = fopen(DEBUG_FILE, "a")) )
            {
                printf("[!!] Error opening debug file '%s'\n", DEBUG_FILE);
                exit(1);
            }
        }

        va_start(list, str);
        vfprintf(fd, str, list);
        va_end(list);

        if( DEBUG_FILE != NULL )
        {
            fclose(fd);
        }
    }
}
